fix(patches): return empty object for unhandled manifests in loadManifest#1151
Conversation
🦋 Changeset detectedLatest commit: a695016 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Hey @vicb - just wanted to check in on this. No rush at all, I know you're probably busy. Just wanted to make sure the approach looks reasonable to you, or if you'd prefer I take it in a different direction. Happy to adjust anything. |
|
Can confirm that is working for me in production after copying this patch into the project using |
|
Need this fix too. |
commit: |
|
LGTM, until this is merged you can use |
| // This handles optional manifests (e.g. subresource-integrity-manifest.json when | ||
| // experimental.sri is not configured) and manifests generated in a different build | ||
| // phase (e.g. per-route react-loadable-manifest.json with Turbopack). | ||
| return {}; |
There was a problem hiding this comment.
I don't think this is the right solution, this will just hide other potential errors, if we know the one that could be null, that's the one we should return an empty object, not everything
There was a problem hiding this comment.
Good call - updated to handle only the specific manifests that Next.js loads with handleMissing: true (traced through route-module.ts in vercel/next.js).
The five optional manifests for loadManifest:
react-loadable-manifest.json- Turbopack per-route, not all routes have dynamic importssubresource-integrity-manifest.json- only whenexperimental.sriconfiguredserver-reference-manifest.json- App Router only, Pages Router never generatesdynamic-css-manifest.json- Pages Router + Webpack onlyfallback-build-manifest.json- only for/_errorpage
Everything else still throws. Same approach for evalManifest - only _client-reference-manifest.js gets a safe default ({ __RSC_MANIFEST: {} }) since it's optional for static metadata routes.
| $PATH = $PATH.replaceAll(${JSON.stringify(sep)}, ${JSON.stringify(posix.sep)}); | ||
| ${returnManifests} | ||
| throw new Error(\`Unexpected evalManifest(\${$PATH}) call!\`); | ||
| return {}; |
There was a problem hiding this comment.
Addressed - evalManifest now only handles _client-reference-manifest.js (optional for static metadata routes per route-module.ts line 343). Returns { __RSC_MANIFEST: {} } as the safe default structure. Everything else still throws.
Address review feedback from @conico974 — instead of returning {} for all unknown manifests (which would hide genuine errors), only handle the specific manifests that Next.js loads with handleMissing: true. loadManifest optional manifests (from vercel/next.js route-module.ts): - react-loadable-manifest.json (Turbopack per-route) - subresource-integrity-manifest.json (experimental.sri) - server-reference-manifest.json (App Router only) - dynamic-css-manifest.json (Pages Router + Webpack only) - fallback-build-manifest.json (/_error page only) evalManifest optional manifests: - _client-reference-manifest.js (static metadata routes) Everything else still throws to surface genuine errors.
This did not work for me, trying to run next 16.2 still receives "Unexpected loadManifest(/.next/server/prefetch-hints.json) call!" running with wrangler dev locally |
|
Hey @nathanschram — we've been testing Next.js 16.2.0 (stable, not canary) on Cloudflare Workers and can confirm this PR is needed alongside #1160 for things to work. We found one issue during testing (after manually applying the patch from this PR locally): some manifests are requested without the Root causeNext.js defines some manifest constants without
When My suggestion for this PRFor each manifest in the fallback list, check both with and without $PATH.endsWith("dynamic-css-manifest.json") || $PATH.endsWith("dynamic-css-manifest")Or strip const normalizedPath = $PATH.replace(/\.json$/, "");
if (normalizedPath.endsWith("dynamic-css-manifest")) return {};After manually applying (locally) #1160 + this PR + the extensionless fix above, I can confirm that our Next.js 16.2.0 app renders successfully on Cloudflare Workers (for Platforms, in our case):
Happy to help with the fix or open a follow-up PR if that's easier. Thanks for this PR! |
conico974
left a comment
There was a problem hiding this comment.
LGTM Thanks for the fix
|
@nathanschram Could You fix the prettier issue please ? |
- Fix prettier formatting in changeset - Strip .json extension before matching optional manifests since Next.js defines some constants without it (SUBRESOURCE_INTEGRITY_MANIFEST, DYNAMIC_CSS_MANIFEST, SERVER_REFERENCE_MANIFEST) - Add prefetch-hints to the optional manifest list (new in Next.js 16.2) - All 236 tests pass, tsc clean, prettier clean Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@conico974 Prettier issue should be fixed now - sorry about that. @matthewvolk Great catch on the extensionless manifests - I've updated the matching to strip @bonadio Added Summary of changes in the latest push:
|

Summary
{}instead of throwing for manifest paths not found during the build-time glob scan inloadManifest()andevalManifest()loadManifest()calls for optional/phase-dependent manifestsProblem
Next.js canary adds
loadManifest()calls for:subresource-integrity-manifest.json- only generated whenexperimental.sriis configured, but loaded unconditionallyreact-loadable-manifest.json- generated by Turbopack, possibly in a different build phaseThe adapter's build-time glob scan doesn't find these files, so the patched function throws at runtime, crashing all dynamic routes with 500.
Fix
Replace the
throw new Error('Unexpected loadManifest...')fallback withreturn {}. This follows the same defensive pattern used by other adapter plugins (instrumentation.ts,find-dir.ts) that return safe defaults for missing files.Test plan
next@canary(16.2.0-canary.53+) using@opennextjs/cloudflareexperimental.sriIS configuredFixes #1141